package com.csw.android.ffmpegtest.media.base

import android.media.AudioFormat
import com.csw.android.dev_utils.ex.CloseableEx.closeIgnoreException
import com.csw.android.ffmpegtest.utils.DataUtils
import java.io.File
import java.io.FileInputStream

object WAVHelper {

    fun getWAVInfo(filePath: String): WAVInfo? {
        var fis: FileInputStream? = null
        try {
            File(filePath).let {
                if (it.exists()) {
                    val fileSize = it.length()
                    fis = FileInputStream(it).apply {
                        //先读取头部
                        val headLength = 4 + 4 + 4 + 4 + 4
                        var buffer = ByteArray(headLength)
                        var len = read(buffer)
                        if (len != buffer.size) {
                            return null
                        }
                        if ('W'.toByte() == buffer[8]
                            && 'A'.toByte() == buffer[9]
                            && 'V'.toByte() == buffer[10]
                            && 'E'.toByte() == buffer[11]
                            && 'f'.toByte() == buffer[12]
                            && 'm'.toByte() == buffer[13]
                            && 't'.toByte() == buffer[14]
                            && ' '.toByte() == buffer[15]
                        ) {
                            //取得format区域长度
                            val formatLength = (DataUtils.byteToInt(16)
                                    or (DataUtils.byteToInt(buffer[17]).shl(8))
                                    or (DataUtils.byteToInt(buffer[18]).shl(16))
                                    or (DataUtils.byteToInt(buffer[19]).shl(24))
                                    )
                            //读取format区域
                            buffer = ByteArray(formatLength)
                            len = read(buffer)
                            if (len != buffer.size && len >= 16) {
                                return null
                            }
                            val isPCM = (DataUtils.byteToInt(buffer[0])
                                    or (DataUtils.byteToInt(buffer[1]).shl(8))
                                    )
                            if (isPCM != 1) {
                                return null
                            }
                            val channels = (DataUtils.byteToInt(buffer[2])
                                    or (DataUtils.byteToInt(buffer[3]).shl(8))
                                    )
                            val sampleRateInHz = (DataUtils.byteToInt(buffer[4])
                                    or (DataUtils.byteToInt(buffer[5]).shl(8))
                                    or (DataUtils.byteToInt(buffer[6]).shl(16))
                                    or (DataUtils.byteToInt(buffer[7]).shl(24))
                                    )
//                            val byteRate = (DataUtils.byteToInt(buffer[8])
//                                    or (DataUtils.byteToInt(buffer[9]).shl(8))
//                                    or (DataUtils.byteToInt(buffer[10]).shl(16))
//                                    or (DataUtils.byteToInt(buffer[11]).shl(24))
//                                    )
//                            val blockAlign = (DataUtils.byteToInt(buffer[12])
//                                    or (DataUtils.byteToInt(buffer[13]).shl(8))
//                                    )
                            val bitsPerSample = (DataUtils.byteToInt(buffer[14])
                                    or (DataUtils.byteToInt(buffer[15]).shl(8))
                                    )
                            return WAVInfo(
                                fileSize - headLength - formatLength - 8,
                                sampleRateInHz,
                                channels,
                                bitsPerSample,
                                if (bitsPerSample == 16) AudioFormat.ENCODING_PCM_16BIT else AudioFormat.ENCODING_PCM_8BIT
                            )
                        }
                    }
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
        } finally {
            fis.closeIgnoreException()
        }
        return null
    }

    /**
     * 获取wav音频文件时长
     *
     * 通过总字节数/每秒字节数得到， 每秒字节数根据采样率，声道数，采样存储带宽决定
     * 48000hz 每秒采样48000次，每次数据用16/8byte存储，每个声道采样一次，单声道每秒就差不多得100k啊，不得了
     * 不压缩这么占带宽
     */
    fun getAudioDuration(wavInfo: WAVInfo): Long {
        val byteRate = wavInfo.sampleRateInHz * wavInfo.channels * wavInfo.bitsPerSample / 8
        return (wavInfo.dataLength * 1000F / byteRate).toLong()
    }

    /**
     * 设置WAV头部信息
     * @param headInfo 44字节的头部信息数组
     * @param dataLength pcm数据长度
     * @param sampleRateInHz 采样率
     * @param channels 声道数量
     * @param encoding PCM编码
     */
    fun setHeadInfo(
        headInfo: ByteArray,
        dataLength: Int,
        sampleRateInHz: Int,
        channels: Int,
        encoding: Int
    ) {
        val bitsPerSample = when (encoding) {
            AudioFormat.ENCODING_PCM_16BIT -> 16
            else -> 8
        }
        val totalLength = dataLength + 44
        val size = totalLength - 8
        headInfo[0] = 'R'.toByte()
        headInfo[1] = 'I'.toByte()
        headInfo[2] = 'F'.toByte()
        headInfo[3] = 'F'.toByte()
        //size
        headInfo[4] = (size and 0xFF).toByte()
        headInfo[5] = (size shr 8 and 0xFF).toByte()
        headInfo[6] = (size shr 16 and 0xFF).toByte()
        headInfo[7] = (size shr 24 and 0xFF).toByte()
        //WAVE
        headInfo[8] = 'W'.toByte()
        headInfo[9] = 'A'.toByte()
        headInfo[10] = 'V'.toByte()
        headInfo[11] = 'E'.toByte()
        //'fmt' chunk
        headInfo[12] = 'f'.toByte()
        headInfo[13] = 'm'.toByte()
        headInfo[14] = 't'.toByte()
        headInfo[15] = ' '.toByte()
        // 4 bytes: size of 'fmt ' chunk
        headInfo[16] = 16
        headInfo[17] = 0
        headInfo[18] = 0
        headInfo[19] = 0
        // format = 1
        //PCM编码
        headInfo[20] = 1
        headInfo[21] = 0
        //单声道 MONO
        headInfo[22] = (channels and 0xFF).toByte()
        headInfo[23] = (channels shr 8 and 0xFF).toByte()
        //sampleRateInHz
        headInfo[24] = (sampleRateInHz and 0xFF).toByte()
        headInfo[25] = (sampleRateInHz shr 8 and 0xFF).toByte()
        headInfo[26] = (sampleRateInHz shr 16 and 0xFF).toByte()
        headInfo[27] = (sampleRateInHz shr 24 and 0xFF).toByte()
        //byteRate
        val byteRate = sampleRateInHz * channels * bitsPerSample / 8
        headInfo[28] = (byteRate and 0xFF).toByte()
        headInfo[29] = (byteRate shr 8 and 0xFF).toByte()
        headInfo[30] = (byteRate shr 16 and 0xFF).toByte()
        headInfo[31] = (byteRate shr 24 and 0xFF).toByte()
        //block align
        val align = channels * bitsPerSample / 8
        headInfo[32] = (align and 0xFF).toByte()
        headInfo[33] = (align shr 8 and 0xFF).toByte()
        //bits per sample
        headInfo[34] = (bitsPerSample and 0xFF).toByte()
        headInfo[35] = (bitsPerSample shr 8 and 0xFF).toByte()
        //data
        headInfo[36] = 'd'.toByte()
        headInfo[37] = 'a'.toByte()
        headInfo[38] = 't'.toByte()
        headInfo[39] = 'a'.toByte()
        headInfo[40] = (dataLength and 0xFF).toByte()
        headInfo[41] = (dataLength shr 8 and 0xFF).toByte()
        headInfo[42] = (dataLength shr 16 and 0xFF).toByte()
        headInfo[43] = (dataLength shr 24 and 0xFF).toByte()
    }

    class WAVInfo(
        val dataLength: Long,
        val sampleRateInHz: Int,
        val channels: Int,
        val bitsPerSample: Int,
        val encoding: Int
    )

}